<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    function observe(target) {
      // 如果 target 是对象，则遍历他
      if (target && typeof target === 'object') {
        Object.keys(target).forEach(key => {
          defineReactive(target, key, target[key])
        })
      }
    }

    function defineReactive(target, key, val) {
      const dep = new Dep()
      // 属性值也可能是object类型，这种情况下需要调用observe进行递归遍历
      observe(val)
      Object.defineProperty(target, key, {
        enumerable: true,
        configurable: false,
        get: function () {
          return val
        },
        set: function (value) {
          val = value
          dep.notify()
        }
      })
    }

    // 定义订阅者类 Dep，主题
    class Dep {
      constructor() {
        // 初始化订阅者队列
        this.subs = []
      }

      // 增加订阅者
      addSub(sub) {
        this.subs.push(sub)
      }

      // 通知订阅者
      notify() {
        this.subs.forEach(sub => {
          sub.update()
        })
      }
    }
  </script>
</body>

</html>